/*
 *用C++11生成随机数
 *参考链接：https://www.bilibili.com/video/BV1DN4y1d7Ze/?spm_id_from=333.999.0.0
 */

#include <iostream>
#include <random>
#include <vector>
#include <string>
#include <algorithm>
#include <numeric>

//生成整数随机数
void TestInt()
{
	std::random_device rnd; //用于生成随机数种子。它通常从硬件层面获取随机性，因此随机性较高，但相对较慢
	std::mt19937 rng(rnd()); //伪随机数生成器类，它使用梅森旋转算法实现，生成的随机数序列几乎不会重复。以初始化std::mt19937伪随机数生成器。
	std::uniform_int_distribution<int> uni(0, 100); //设置生成随机数的范围 用于定义生成均匀分布整数随机数的分布器
	for (int i = 0; i < 10; ++i)
	{
		size_t num = uni(rng); //生成随机数
		std::cout << num << "\t";
	}
	std::cout << "\n===========================================\n";
}

//生成浮点数的随机数
void TestFloat()
{
	std::random_device rnd;
	std::mt19937 rng(rnd());
	std::uniform_real_distribution<float> uni(0.0f, 1.0f);
	for (int i = 0; i < 10; ++i)
	{
		float num = uni(rng);
		std::cout << num << "\t";
	}
	std::cout << "\n===========================================\n";
}

//======================================================================

//用C++封装一个xorshift32随机种子算法，代替mt19937伪随机数生成器
//xorshift32 算法的种子不能为0
struct xorshift32
{
	uint32_t a;
	explicit xorshift32(size_t seed = 0) : a(static_cast<uint32_t>(seed + 1)) { /*std::cout << "seed = " << seed << std::endl;*/ }

	using result_type = uint32_t;

	//constexpr(编译期求值) 用于修饰函数的返回值，这样的函数又称为 常量表达式函数，返回值为常量，可用于定义数组
	//noexcept 表示函数不会抛出异常
	constexpr uint32_t operator()() noexcept
	{
		uint32_t x = a;
		x ^= x << 13;
		x ^= x >> 17;
		x ^= x << 5;
		//std::cout << "a = " << a << std::endl;
		return a = x;
	}
	
	static constexpr uint32_t min() noexcept
	{
		return 1;
	}

	static constexpr uint32_t max() noexcept
	{
		return UINT32_MAX;
	}
	
};

void TestXorshift32()
{
	xorshift32 rng(std::random_device{}()); //设置种子,{}为构造，()为调用
	std::uniform_int_distribution<int> uni(0, 100);
	for (int i = 0; i < 10; ++i)
	{
		int num = uni(rng);
		std::cout << num  << "\t";
	}
	std::cout << "\n===========================================\n";
}

//===============================================================

//王氏哈希
struct wangshash {
	uint32_t a;

	explicit wangshash(size_t seed = 0) : a(static_cast<uint32_t>(seed)) {
	}

	using result_type = uint32_t;

	constexpr uint32_t operator()() noexcept {
		uint32_t x = a;
		x = (x ^ 61) ^ (x >> 16);
		x *= 9;
		x = x ^ (x >> 4);
		x *= 0x27d4eb2d;
		x = x ^ (x >> 15);
		return a = x;
	}

	static constexpr uint32_t min() noexcept {
		return 0;
	}

	static constexpr uint32_t max() noexcept {
		return UINT32_MAX;
	}
};


void TestWangshash()
{
	std::cout << "TestWangshash" << std::endl;
	for (size_t i = 0; i < 100; i++)
	{
		xorshift32 rng(i);
		std::uniform_int_distribution<int> uni(0, 100);
		std::cout << uni(rng) << "\t";
	}
	std::cout << "\n===========================================\n";

	for (size_t i = 0; i < 100; i++)
	{
		wangshash rng(i);
		std::uniform_int_distribution<int> uni(0, 100);
		std::cout << uni(rng) << "\t";
	}
	std::cout << "\n===========================================\n";
}

//===============================================================

//实现一个根据概率随机数的方法
void Test()
{
	std::vector<float> gailv = { 0.6f, 0.25f, 0.1f, 0.05f };
	std::vector<float> gailv_scanned;//0.6     0.85    0.9     1
	//back_inserter中的=符号重载为了pushback(),所以用back_inserter插入元素时可以不用指定gailv_scanned的容量
	//用于执行一个累积操作，将输入范围中的元素依次累积，并将累积的结果存储在输出范围中
	std::inclusive_scan(gailv.begin(), gailv.end(), std::back_inserter(gailv_scanned));//C++17
	//for (const auto& t : gailv_scanned)
	//{
	//	std::cout << t << "\t";
	//}
	//std::cout << "\n";

	std::vector<std::string> lian = { "普通1", "稀有2", "珍贵3", "绝世4" };
	std::mt19937 rng{ std::random_device{}() };
	std::uniform_real_distribution<float> unf(0.0f, 1.0f);
	auto genlian = [&]() -> std::string {
		float f = unf(rng);
		//在有序容器中，找到第一个大于或等于指定值的元素位置（迭代器）
		auto it = std::lower_bound(gailv_scanned.begin(), gailv_scanned.end(), f);
		if (it == gailv_scanned.end()) return "";
		return lian[it - gailv_scanned.begin()];
	};

	for (int i = 0; i < 100; ++i)
	{
		std::cout << genlian() << std::endl;
	}
}

//===============================================================

constexpr int aaa(int a)
{
	int b = 1 + a;
	return b;
}

int main(void)
{
	TestInt();
	TestFloat();
	TestXorshift32();
	TestWangshash();
	Test();

	const int a = 1;
	constexpr int b = aaa(a);
	int str[b] = { 0 };
	std::cout << str[0];

	return 0;
}
